NOVA中的notification机制介绍与定制开发 | 您所在的位置:网站首页 › registration notification的中文 › NOVA中的notification机制介绍与定制开发 |
个人blog:http://www.sskywatcher.com/blog 由sskywatcher翻译,转载请注明出处 目录 概述 不支持多版本的经典通知 支持多版本的新型通知 如何增加一个新的notification(规程与示例) 模块nova.notifications.objects.base 通知的负载中应该包含哪些内容? 当前已存在的通知 概述与 OpenStack 的其他服务模块类似,Nova 使用 oslo.messaging 模块提供的 Notifier 类 项消息总线发出通知消息。 从一个通知消息的消费者角度来看,一个通知消息(notification) 包含两个部分:一个由 oslo.messaging 定义好的有固定结构格式的消息封皮(envelope )部分、 一个由通知消息的发出者服务定义的负载(payload)。消息封皮的格式如下所示: { "priority": , "event_type": , "timestamp": , "publisher_id": , "message_id": , "payload": }在本地环境中配置 nova 配置文件的一下部分,可以完全关闭 Notification 功能 : [oslo_messaging_notifications] driver = noopNova 中有两种不同类型的通知 : 负载消息没有版本之分的经典的通知消息、支持多版本负载消息的通知消息。 不支持多版本的经典通知Nova 的代码使用 nova.rpc.get_notifier 来获取已经配置好的 oslo.messaging Notifier 对象, 使用olso组件提供的Notifier 的成员方法来发送通知。 get_notifier 调用的参数以及 oslo.messaging 模块配置的选项 "driver" 和 "topics"决定了获取到的Notifier 对象的配置。Nova 中有多个配置选项,这些选项用于指定 notification 的类型,如下例: notifications.notify_on_state_change, notifications.default_level, 等等。 发送通知的代码中定义了无多版本支持的通知的负载的结构,这种格式没有文档记载说明,也不考虑任何的后向兼容性。 支持多版本的新型通知支持多版本的新型通知资格概念之所以被提出来,就是为了弥补老式通知的缺点。 oslo.messaging 给这种新型通知提供的消息封皮部分的结构与老式通知消息的完全相同。 但是负载部分不再是一个自由定义的字典格式,相应的部分被 olso 的 versionedobjects 模块的对象所取代。 举一个例子:service.update 通知消息的格式如下所示: { "priority":"INFO", "payload":{ "nova_object.namespace":"nova", "nova_object.name":"ServiceStatusPayload", "nova_object.version":"1.0", "nova_object.data":{ "host":"host1", "disabled":false, "last_seen_up":null, "binary":"nova-compute", "topic":"compute", "disabled_reason":null, "report_count":1, "forced_down":false, "version":2 } }, "event_type":"service.update", "publisher_id":"nova-compute:host1" }序列化后的 oslo versionedobject 作为负载向消费者提供了一个版本号,这样,消费者就可以检测到消息中的格式是否发生了变化。对于支持多版本的通知负载,Nova 作出了以下几个约定: 当且仅当负载中的 nova_object.data 字段的语法或者语义发生变化时,负载中 nova_object.version 字段定义的版本号将会增加。使用次级版本号主要提示后向兼容性的中负载发生了较小的改变,即仅仅向负载中增加了新的字段,这样对于一个正确编写的消费者来说,不需要做出任何改变依然可以正常地消息这个通知消息。主版本号主要用于提示后向兼容性中的负载某些大的变动。比如负载可能移除了某些字段、字段的类型发生了变更等等。除了 ‘nova_object.data’ 和 ‘nova_object.version’ 字段外,每个负载中都有一个附加的字段 ‘nova_object.name’,这个字段包含了负责类型在 nova 模块内部表达式的名称。客户端的代码不能基于这个名称来编写。Nova 的配置选项 notifications.notification_format 可以指定用哪一种格式来发送通知。 可选的值包括: "unversioned", "versioned“, "both",默认值是 "both"。 相比于老式的通知,新的通知可以被发送到不同的 topic 。默认情况下,他们将被发送到 ‘versioned_notifications’ ,你可以在Nova 的配置文件 nova.conf 中使用 notifications.versioned_notifications_topics 这个选项来配置它。 如何增加一个新的notification(规程与示例)为了支持以上提及的约定,nova 代码中每个支持多版本的通知都是以 oslo versionedobjects 作为模板。 每个支持多版本的通知应该继承自 nova.notifications.objects.base.NotificationBase ,该基类已经定义了通知类的3个强制性的字段:event_type, publisher 和 priority。新的通知类应该增加一个新字段 payload 并制定一个合适的负载类型。 通知中的负载对象(payload) 应该继承自 nova.notifications.objects.base.NotificationPayloadBase, 并且需要将负载字段定义为对应的 versionedobject 字段。 以下将列出各基类: 模块nova.notifications.objects.baseclass EventType(object, action, phase=None) 基类: nova.notifications.objects.base.NotificationObject to_notification_event_type_field() 将对象序列化的方法。 class NotificationBase(**kwargs) 基类: nova.notifications.objects.base.NotificationObject 这是支持多版本的通知类的基类。 每个子类都需要定义 ‘payload’ 字段。 emit(context) 发送通知。 class NotificationObject(**kwargs) 基类: nova.objects.base.NovaObject 这是每个关联于支持多版本对象的通知类的基类。 class NotificationPayloadBase 基类: nova.notifications.objects.base.NotificationObject 支持多版本的通知中负载类(payload )的基类。 populate_schema(set_none=True, **kwargs) 根据 SCHEMA 和源对象填充出对象 参数:kwargs –包含了在 SCHEMA 中使用 key 值定义的源对象的字典class NotificationPublisher(host, source) 基类: nova.notifications.objects.base.NotificationObject notification_sample(sample) 这是一个给通知类加上示例信息的类装饰器,主要为生成文档服务。 参数列表:sample –nova版本库中 doc/notification_samples/ 目录下 json文件的路径。请注意,通知对象不要注册到 NovaObjectRegistry ,以避免将通知对象和 nova 内部的对象混淆。相应的解决方法是在每个具体的通知对象使用 register_notification 装饰器。 下面示例展示了新建一个消息 myobject.update 需要定义的必要的模型类: @notification.notification_sample('myobject-update.json') @object_base.NovaObjectRegistry.register.register_notification class MyObjectNotification(notification.NotificationBase): # Version 1.0: Initial version VERSION = '1.0' fields = { 'payload': fields.ObjectField('MyObjectUpdatePayload') } @object_base.NovaObjectRegistry.register.register_notification class MyObjectUpdatePayload(notification.NotificationPayloadBase): # Version 1.0: Initial version VERSION = '1.0' fields = { 'some_data': fields.StringField(), 'another_data': fields.StringField(), }接下来可以使用下面的示例代码来讲通知消息填充和发送: payload = MyObjectUpdatePayload(some_data="foo", another_data="bar") MyObjectNotification( publisher=notification.NotificationPublisher.from_service_obj( ), event_type=notification.EventType( object='myobject', action=fields.NotificationAction.UPDATE), priority=fields.NotificationPriority.INFO, payload=payload).emit(context)上面的示例代码将会产生下面格式的通知消息: { "priority":"INFO", "payload":{ "nova_object.namespace":"nova", "nova_object.name":"MyObjectUpdatePayload", "nova_object.version":"1.0", "nova_object.data":{ "some_data":"foo", "another_data":"bar", } }, "event_type":"myobject.update", "publisher_id":":" }通过在payload类中增加一个定义了已存在对象的字段和新payload对象的字段映射关系的 SCHEMA 字段,可以实现重用已存在的versionedobject 。举个例子, service.status 这个通知在定义自己的负载类时重用了 nova.objects.service.Service 对象: @notification.notification_sample('service-update.json') @object_base.NovaObjectRegistry.register.register_notification class ServiceStatusNotification(notification.NotificationBase): # Version 1.0: Initial version VERSION = '1.0' fields = { 'payload': fields.ObjectField('ServiceStatusPayload') } @object_base.NovaObjectRegistry.register.register_notification class ServiceStatusPayload(notification.NotificationPayloadBase): SCHEMA = { 'host': ('service', 'host'), 'binary': ('service', 'binary'), 'topic': ('service', 'topic'), 'report_count': ('service', 'report_count'), 'disabled': ('service', 'disabled'), 'disabled_reason': ('service', 'disabled_reason'), 'availability_zone': ('service', 'availability_zone'), 'last_seen_up': ('service', 'last_seen_up'), 'forced_down': ('service', 'forced_down'), 'version': ('service', 'version') } # Version 1.0: Initial version VERSION = '1.0' fields = { 'host': fields.StringField(nullable=True), 'binary': fields.StringField(nullable=True), 'topic': fields.StringField(nullable=True), 'report_count': fields.IntegerField(), 'disabled': fields.BooleanField(), 'disabled_reason': fields.StringField(nullable=True), 'availability_zone': fields.StringField(nullable=True), 'last_seen_up': fields.DateTimeField(nullable=True), 'forced_down': fields.BooleanField(), 'version': fields.IntegerField(), } def populate_schema(self, service): super(ServiceStatusPayload, self).populate_schema(service=service)如果定义了 SCHEMA 字段, 那么 payload 必须先使用 populate_schema 调用填充后才能发送: payload = ServiceStatusPayload() payload.populate_schema(service=) ServiceStatusNotification( publisher=notification.NotificationPublisher.from_service_obj( ), event_type=notification.EventType( object='service', action=fields.NotificationAction.UPDATE), priority=fields.NotificationPriority.INFO, payload=payload).emit(context)SCHEMA 中的每一个项目遵循以下语法: : (,)SCHEMA 中定义的字段拥有以下语义。 当调用了 populate_schema 方法时, SCHEMA 的文本内容将被枚举并且将指定参数对象的字段的值拷贝至请求的 payload 对象对应字段中。所以上述示例中, payload 对象的 host 字段通过调用 populate_schema 被填充为 service 对象的 host 字段的值。 一个通知的 payload 可以重用多个已存在对象的字段值。通知也可以同时使用新定义的字段和重用字段。 注意,可以使用2种不同的方式来创建通知的发布者实例。可以通过带 host 和 binary 字符串参数实例化 NotificationPublisher 对象,也可以通过通过调用 NotificationPublisher.from_service_obj 方法直接生成一个 Service 对象。 支持多版本的通知需要在 doc/sample_notifications 目录下维护一个示例文件, 并且该通知类需要使用 notification_sample 装饰器装饰。比如, service.update 的示例文件保存在 doc/sample_notifications/service-update.json ,也相应地使用装饰器装饰了 ServiceUpdateNotification 类。 在 Nova 代码中通知的负载 (payload)类可以使用继承来避免多次定义相同片段的 payload 。但是,在通知中必须小心的创建直接使用的叶类,避免将来因为叶类的名字已经存在而导致不得不需要增加额外的继承等级来修改类名的问题。如果实在无法避免并且仅仅需要改变类名的话,那么新 payload 的版本号应该和没被改名前的版本保持一致。参考https://review.openstack.org/#/c/463001/ 。如果改变除了改名以外包含任意其他改动(比如 增加新字段) ,那么新 payload 的版本号应该比没被改名前的版本号要高,示例请参考 https://review.openstack.org/#/c/453077/ 。 通知的负载中应该包含哪些内容?以下仅仅列出指导性意见,你必须结合实际的应用场景来考虑。 每个条目的唯一索引号(e.g. uuid) , 唯一索引可以被用来使用 REST API 来查询该条目,是的消息则可以获取更多该条目的信息。考虑包含那些促使你发送通知的事件相关的一些字段。举个例子,比如一个自断发生改变触发你发送一个更新的通知,那么你应该在通知的负载中包含这个字段。一个更新通知应该包含那些条目中发生变化的信息。可以通过填充负载中的 nova_object.changes 部分(注意,在通知框架中暂时还不支持这么做),也可以在负载中同时发送该条目的旧状态和新状态。永远不要在 payload 中包含一个 Nova 内部使用的类。你应该新建一个类,并且使用 SCHEMA 和字段映射机制。这种改进的方式可以让通知中负载类的演进与 Nova 中内部类的演进相解耦。一个删除通知应该包含和创建通知或者更新通知相同的字段信息。这使得消费者可以在保持对某些字段过滤 (e.g. project_id)的情况下依然可以接收到删除通知。 当前已存在的通知请参考英文原文的列表,此处不一一列举。 本文翻译自英文原文:https://docs.openstack.org/nova/latest/reference/notifications.html |
CopyRight 2018-2019 实验室设备网 版权所有 |